﻿#include "widgetdata.h"
#include "framelesshelperprivate.h"
#include "cursorposcalculator.h"

#include<QMouseEvent>




WidgetData::WidgetData(FrameLessHelperPrivate *_d, QWidget *pTopLevelWidget)
{
    d = _d;
    widgetPtr = pTopLevelWidget;
    isLeftButtonPressed = false;
    isCursorShapeChanged = false;
    isLeftButtonTitlePressed = false;
    rubberBand = nullptr;
    windowFlags = widgetPtr->windowFlags();
    widgetPtr->setWindowFlags(Qt::FramelessWindowHint | windowFlags);
    widgetPtr->setMouseTracking(true);
    widgetPtr->setAttribute(Qt::WA_Hover, true);
    updateRubberBandStatus();
}

WidgetData::~WidgetData()
{
    widgetPtr->setMouseTracking(false);
    widgetPtr->setWindowFlags(windowFlags);
    widgetPtr->setAttribute(Qt::WA_Hover, false);

    delete rubberBand;
    rubberBand = NULL;
}

QWidget* WidgetData::widget()
{
    return widgetPtr;
}

void WidgetData::handleWidgetEvent(QEvent *event)
{
    switch (event->type())
    {
    default:
        break;
    case QEvent::MouseButtonPress:
        handleMousePressEvent(static_cast<QMouseEvent*>(event));
        break;
    case QEvent::MouseButtonRelease:
        handleMouseReleaseEvent(static_cast<QMouseEvent*>(event));
        break;
    case QEvent::MouseMove:
        handleMouseMoveEvent(static_cast<QMouseEvent*>(event));
        break;
    case QEvent::Leave:
        handleLeaveEvent(static_cast<QMouseEvent*>(event));
        break;
    case QEvent::HoverMove:
        handleHoverMoveEvent(static_cast<QHoverEvent*>(event));
        break;
    }
}

void WidgetData::updateRubberBandStatus()
{
    if (d->isRubberBandOnMove || d->isRubberBandOnResize)
    {
        if (NULL == rubberBand)
            rubberBand = new QRubberBand(QRubberBand::Rectangle);
    }
    else
    {
        delete rubberBand;
        rubberBand = NULL;
    }
}

void WidgetData::updateCursorShape(const QPoint &gMousePos)
{
    if (widgetPtr->isFullScreen() || widgetPtr->isMaximized())
    {
        if (isCursorShapeChanged)
        {
            widgetPtr->unsetCursor();
        }
        return;
    }

    moveMousePos.recalculate(gMousePos, widgetPtr->frameGeometry());

    if(moveMousePos.isOnTopLeftEdge || moveMousePos.isOnBottomRightEdge)
    {
        widgetPtr->setCursor( Qt::SizeFDiagCursor );
        isCursorShapeChanged = true;
    }
    else if(moveMousePos.isOnTopRightEdge || moveMousePos.isOnBottomLeftEdge)
    {
        widgetPtr->setCursor( Qt::SizeBDiagCursor );
        isCursorShapeChanged = true;
    }
    else if(moveMousePos.isOnLeftEdge || moveMousePos.isOnRightEdge)
    {
        widgetPtr->setCursor( Qt::SizeHorCursor );
        isCursorShapeChanged = true;
    }
    else if(moveMousePos.isOnTopEdge || moveMousePos.isOnBottomEdge)
    {
        widgetPtr->setCursor( Qt::SizeVerCursor );
        isCursorShapeChanged = true;
    }
    else
    {
        if (isCursorShapeChanged)
        {
            widgetPtr->unsetCursor();
            isCursorShapeChanged = false;
        }
    }
}

void WidgetData::resizeWidget(const QPoint &gMousePos)
{
    QRect origRect;

    if (d->isRubberBandOnResize)
        origRect = rubberBand->frameGeometry();
    else
        origRect = widgetPtr->frameGeometry();

    int left = origRect.left();
    int top = origRect.top();
    int right = origRect.right();
    int bottom = origRect.bottom();
    origRect.getCoords(&left, &top, &right, &bottom);

    int minWidth = widgetPtr->minimumWidth();
    int minHeight = widgetPtr->minimumHeight();

    if (pressedMousePos.isOnTopLeftEdge)
    {
        left = gMousePos.x();
        top = gMousePos.y();
    }
    else if (pressedMousePos.isOnBottomLeftEdge)
    {
        left = gMousePos.x();
        bottom = gMousePos.y();
    }
    else if (pressedMousePos.isOnTopRightEdge)
    {
        right = gMousePos.x();
        top = gMousePos.y();
    }
    else if (pressedMousePos.isOnBottomRightEdge)
    {
        right = gMousePos.x();
        bottom = gMousePos.y();
    }
    else if (pressedMousePos.isOnLeftEdge)
    {
        left = gMousePos.x();
    }
    else if (pressedMousePos.isOnRightEdge)
    {
        right = gMousePos.x();
    }
    else if (pressedMousePos.isOnTopEdge)
    {
        top = gMousePos.y();
    }
    else if (pressedMousePos.isOnBottomEdge)
    {
        bottom = gMousePos.y();
    }

    QRect newRect(QPoint(left, top), QPoint(right, bottom));

    if (newRect.isValid())
    {
        if (minWidth > newRect.width())
        {
            if (left != origRect.left())
                newRect.setLeft(origRect.left());
            else
                newRect.setRight(origRect.right());
        }
        if (minHeight > newRect.height())
        {
            if (top != origRect.top())
                newRect.setTop(origRect.top());
            else
                newRect.setBottom(origRect.bottom());
        }

        if (d->isRubberBandOnResize)
        {
            rubberBand->setGeometry(newRect);
        }
        else
        {
            widgetPtr->setGeometry(newRect);
        }
    }
}

void WidgetData::moveWidget(const QPoint& gMousePos)
{
    if (d->isRubberBandOnMove)
    {
        rubberBand->move(gMousePos - ptDragPos);
    }
    else
    {
        widgetPtr->move(gMousePos - ptDragPos);
    }
}

void WidgetData::handleMousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        isLeftButtonPressed = true;
        isLeftButtonTitlePressed = event->pos().y() < moveMousePos.titleHeight;

        QRect frameRect = widgetPtr->frameGeometry();
        pressedMousePos.recalculate(event->globalPos(), frameRect);

        ptDragPos = event->globalPos() - frameRect.topLeft();

        if (pressedMousePos.isOnEdges)
        {
            if (d->isRubberBandOnResize)
            {
                rubberBand->setGeometry(frameRect);
                rubberBand->show();
            }
        }
        else if (d->isRubberBandOnMove)
        {
            rubberBand->setGeometry(frameRect);
            rubberBand->show();
        }
    }
}

void WidgetData::handleMouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        isLeftButtonPressed = false;
        isLeftButtonTitlePressed = false;
        pressedMousePos.reset();
        if (rubberBand && rubberBand->isVisible())
        {
            rubberBand->hide();
            widgetPtr->setGeometry(rubberBand->geometry());
        }
    }
}

void WidgetData::handleMouseMoveEvent(QMouseEvent *event)
{
    if (isLeftButtonPressed)
    {
        if (d->isWidgetResizable && pressedMousePos.isOnEdges)
        {
            resizeWidget(event->globalPos());
        }
        else if (d->isWidgetMovable && isLeftButtonTitlePressed)
        {
            moveWidget(event->globalPos());
        }
    }
    else if (d->isWidgetResizable)
    {
        updateCursorShape(event->globalPos());
    }
}

void WidgetData::handleLeaveEvent(QEvent *event)
{
    Q_UNUSED(event);
    if (!isLeftButtonPressed)
    {
        widgetPtr->unsetCursor();
    }
}

void WidgetData::handleHoverMoveEvent(QHoverEvent *event)
{
    if (d->isWidgetResizable)
    {
        updateCursorShape(widgetPtr->mapToGlobal(event->pos()));
    }
}
